package nciae.db.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.segments.MergeSegments;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import nciae.db.common.CommonResult;
import nciae.db.conf.JwtUtil;
import nciae.db.mapper.*;
import nciae.db.pojo.dto.*;
import nciae.db.pojo.entity.*;
import nciae.db.pojo.vo.ApiGetDateLogVO;
import nciae.db.pojo.vo.ApiStudentLoginVO;
import nciae.db.pojo.vo.ApiTotalScoreVO;
import nciae.db.pojo.vo.StudentVO;
import nciae.db.service.StudentService;
import nciae.db.utils.FileUploadUtils;
import org.apache.poi.ss.usermodel.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.InputStream;
import java.math.BigDecimal;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

@Service
@Slf4j
public class StudentServiceImpl extends ServiceImpl<StudentMapper, Student> implements StudentService {


    @Autowired
    private StudentMapper studentMapper;

    @Autowired
    private ProjectMapper projectMapper;

    @Autowired
    private ClassMapper classMapper;
    @Autowired
    private CourseMapper courseMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private ExpertMapper expertMapper;

    @Autowired
    private SettingsMapper settingsMapper;

    @Autowired
    private LogMapper logMapper;

    @Autowired
    private AttendanceMapper attendanceMapper;

    @Autowired
    private HomeworkDetailMapper homeworkDetailMapper;

    @Autowired
    private HomeworkMapper homeworkMapper;



    @Override
    public CommonResult<List<StudentVO>> search(Integer page, Integer size, String name, String department, String tel, String project, String classs,String expert) {
        CommonResult<List<StudentVO>>  rs = new CommonResult<>();
        try{
            Page<Student> pg = new Page<>(page,size);
            QueryWrapper<Student> queryWrapper = new QueryWrapper<>();
            if(name!=null&&!name.isEmpty()){
                queryWrapper.eq("name",name);
            }
            if(department!=null&&!department.isEmpty()){
                queryWrapper.eq("department",department);
            }
            if(tel!=null&&!tel.isEmpty()){
                queryWrapper.eq("tel",tel);
            }
            if(project!=null&&!project.isEmpty()){
                QueryWrapper<Project> wrapper = new QueryWrapper<>();
                wrapper.eq("project_name", project).last("limit 1");
                Project p = projectMapper.selectOne(wrapper);
                queryWrapper.eq("project_id", p.getId());
            }
            if(classs!=null&&!classs.isEmpty()){
                QueryWrapper<Classs> wrapper = new QueryWrapper<>();
                wrapper.eq("class_name", classs).last("limit 1");
                Classs c = classMapper.selectOne(wrapper);
                queryWrapper.eq("class_id", c.getId());
            }
            if(expert!=null&&!expert.isEmpty()){
                QueryWrapper<Expert> wrapper = new QueryWrapper<>();
                wrapper.eq("name", expert).last("limit 1");
                Expert d = expertMapper.selectOne(wrapper);
                queryWrapper.eq("expert_id", d.getId());
            }
            studentMapper.selectPage(pg,queryWrapper);
            List<Student> list = pg.getRecords();
            List<StudentVO> listVO = getStudentVOs(list);
            long count = pg.getTotal();
            rs.setCode(0);
            rs.setMsg("查询成功");
            rs.setCount(count);
            rs.setData(listVO);
            return rs;
        }catch (Exception e){
            rs.setCode(-1);
            rs.setMsg("发生错误"+e.getMessage());
            return rs;
        }
    }

    @Override
    public CommonResult<Boolean> delete(Integer id) {
        CommonResult<Boolean> rs = new CommonResult<>();
        try{

            Student student = studentMapper.selectById(id);
            if(student!=null){
                Integer classId = student.getClassId();
                List<HomeworkDetail> homeworkDetails = homeworkDetailMapper.getHomeworkDetails(id);
                int code = FileUploadUtils.deleteStudentAllFiles(student).getCode();
                if (code == 200) {
                    logMapper.deleteByUserId(student.getId());
                    for(HomeworkDetail hd : homeworkDetails){
                        homeworkDetailMapper.delHomeworkDetails(hd.getId());
                        homeworkMapper.homeworkCountCorrect(hd.getHomeworkId(), hd.getIsRead());
                    }
                    int k = studentMapper.deleteById(id);
                    if(k>0){
                        classMapper.refreshClassSize(classId);
                        rs.setCode(0);
                        rs.setMsg("删除成功");
                        return rs;
                    }
                }
            }
            rs.setCode(-1);
            rs.setMsg("删除失败");
            return rs;
        }catch (Exception exception){
            rs.setCode(-1);
            rs.setMsg("发生错误：" +exception.getMessage());
            return rs;
        }
    }

    @Override
    public StudentVO getUserInfo(Integer id) {
        Student student = studentMapper.selectById(id);
        return getStudentVO(student);
    }

    @Override
    public CommonResult<Boolean> save(StudentUpdateRequest student) {
        CommonResult<Boolean> result = new CommonResult<>();
        String project = student.getProject();
        Student NewStudent = new Student();
        if(project!=null){
            Project p = projectMapper.selectOne(new QueryWrapper<Project>().eq("project_name",project).last("limit 1"));
            if(p != null){
                NewStudent.setProjectId(p .getId());
            }
        }
        String classes = student.getClasss();
        if(classes!=null){
            Classs c = classMapper.selectOne(new QueryWrapper<Classs>().eq("class_name",classes).last("limit 1"));
            if(c != null){
                NewStudent.setClassId(c.getId());
            }
        }
        BeanUtils.copyProperties(student,NewStudent);
        int i;
        if(NewStudent.getId() == 0){
            NewStudent.setUserPwd("123456");
            i = studentMapper.insert(NewStudent);
            if(i>0){
                classMapper.refreshClassSize(NewStudent.getClassId());
                result.setCode(0);
                result.setMsg("修改成功");
                return result;
            }
        }else{
            i = studentMapper.updateById(NewStudent);
            if(i>0){
                result.setCode(0);
                result.setMsg("修改成功");
                return result;
            }
        }
        result.setCode(-1);
        result.setMsg("修改失败");
        return result;
    }

    @Override
    public CommonResult<String> uploadDairyFile(MultipartFile file, Long userId, Long projectId) {
        return null;
    }

    private List<StudentVO> getStudentVOs(List<Student> list) {
        ArrayList<StudentVO> studentVOS = new ArrayList<>();
        for (Student s:list){
            studentVOS.add(getStudentVO(s));
        }
        return studentVOS;
    }

    private StudentVO getStudentVO(Student student) {
        StudentVO studentVO = new StudentVO();
        BeanUtils.copyProperties(student,studentVO);
        //设置学员对应的项目
        Integer projectId = student.getProjectId();
        Project project = projectMapper.selectById(projectId);
        studentVO.setProject(project);

        //设置学员对应的班级
        Integer classId = student.getClassId();
        Classs classs = classMapper.selectById(classId);
        studentVO.setClasss(classs);
        //设置学员对应的专家
        Integer expertId = student.getExpertId();
        Expert expert = expertMapper.selectById(expertId);
        studentVO.setExpert(expert);

        return studentVO;
    }

    /**
     * 根据班级id查询所有学员
     * @param classId
     * @return
     */
    @Override
    public List<Student> getStudentsByClassId(Long classId) {
        return studentMapper.selectList(new QueryWrapper<Student>().eq("class_id", classId));
    }

    /**
     * 重置密码为123456
     * @param id
     * @return
     */
    @Override
    public boolean resetPassword(Long id) {
        UpdateWrapper<Student> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", id);
        updateWrapper.set("user_pwd", "123456");
        // 执行更新操作
        // 返回是否更新成功
        return studentMapper.update(null, updateWrapper) > 0;
    }

    @Override
    @Transactional
    public CommonResult<Integer> batchImport(String className, String chargerName,String projectName, MultipartFile file) {
        CommonResult<Integer> result = new CommonResult<>();
        //文件不能为空
        if(file.isEmpty()){
            result.setCode(-1);
            result.setMsg("文件为空");
            return result;
        }
        try {
            InputStream inputStream = file.getInputStream();
            Workbook workbook = WorkbookFactory.create(inputStream);
            Sheet sheet = workbook.getSheetAt(0);

            int firstRowNum = sheet.getFirstRowNum() + 1;
            int lastRowNum = sheet.getLastRowNum();

            ArrayList<Student> students = new ArrayList<>();
            // 插入班级数据并获取班级ID
            QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
            userQueryWrapper.eq("real_name", chargerName).eq("role", "班主任");
            User chargerUser = userMapper.selectOne(userQueryWrapper);
            if(chargerUser == null){
                result.setCode(-3);
                result.setMsg("班主任不存在");
                return result;
            }

            //设置项目ID
            Integer ProjectId;
            QueryWrapper<Project> projectQueryWrapper = new QueryWrapper<>();
            projectQueryWrapper.eq("project_name", projectName);
            Project project = projectMapper.selectOne(projectQueryWrapper);
            Integer num = project.getNum();
            if(lastRowNum > num){
                result.setCode(-3);
                result.setMsg("班级人数超过项目人数");
                return result;
            }
            if(project == null){
                result.setCode(-3);
                result.setMsg("项目不存在");
                return result;
            }else{
                ProjectId = project.getId();
            }

            //插入班级并获取班级ID
            Integer ClassesId;
            Classs classs = new Classs();
            classs.setProjectId(project.getId());
            classs.setClassName(className);
            classs.setNum(lastRowNum);
            classs.setChargerId(chargerUser.getId());
            classs.setChargerName(chargerUser.getRealName());
            int insertRes = classMapper.insert(classs);
            if(insertRes == 0){
                result.setCode(-3);
                result.setMsg("班级设置失败");
                return result;
            }else{
                ClassesId = classs.getId();
            }

            for(int i=firstRowNum; i<=lastRowNum; i++){
                Student student = new Student();
                Row row = sheet.getRow(i);
                if(row == null){
                    continue;
                }

                //设置姓名
                Cell NameCell = row.getCell(0);
                String userName = NameCell.toString();
                if(userName == null || userName.isEmpty()){
                    student.setName(" ");
                }else{
                    student.setName(NameCell.toString());
                }

                //设置工作单位
                Cell DepartmentCell = row.getCell(1);
                if(DepartmentCell == null){
                    student.setDepartment("");
                }else{
                    student.setDepartment(DepartmentCell.toString());
                }

                //设置电话
                Cell TelCell = row.getCell(2);
                String phoneStr = TelCell.toString();
                if(phoneStr == null || phoneStr.isEmpty()){
                    student.setTel("");
                }else{
                    if (TelCell.getCellType() == CellType.NUMERIC) {
                        phoneStr =  BigDecimal.valueOf(TelCell.getNumericCellValue()).stripTrailingZeros().toPlainString();
                        student.setTel(phoneStr);
                    }
                    else{
                        student.setTel(phoneStr);
                    }
                }

                //设置密码
                Cell PwdCell = row.getCell(3);
                String pwdStr = PwdCell.toString();
                if(pwdStr == null || pwdStr.isEmpty()){
                    student.setUserPwd("");
                }else{
                    if (PwdCell.getCellType() == CellType.NUMERIC) {
                        pwdStr =  BigDecimal.valueOf(PwdCell.getNumericCellValue()).stripTrailingZeros().toPlainString();
                        student.setUserPwd(pwdStr);
                    }
                    else{
                        student.setUserPwd(pwdStr);
                    }
                }

                //设置项目ID
                student.setProjectId(ProjectId);
                //设置班级ID
                student.setClassId(ClassesId);


                students.add(student);
            }
            inputStream.close();
            workbook.close();
            for(Student student: students){
                studentMapper.insert(student);
            }

            result.setCode(0);
            result.setMsg("导入成功");
            result.setData(students.size());
            return result;
        }catch (Exception e){
            result.setCode(-2);
            result.setMsg("文件读取失败");
            return result;
        }
    }

    //处理专家分配

    /**
     * 将学生分配给专家
     *
     * @param studentIds 学生ID列表
     * @param expertId 专家ID
     * @return 分配结果
     * TODO: 指导名额最大值待定
     */
    @Override
    public CommonResult<Boolean> assignStudentsToExpert(List<Integer> studentIds, Integer expertId) {
        CommonResult<Boolean> result = new CommonResult<>();
        Settings settings = settingsMapper.getSettings();
        Integer MAX_places=settings.getStuMaxNum();
        // 获取专家信息
        Expert expert = expertMapper.selectById(expertId);

        // 如果专家不存在
        if (expert == null) {
            result.setCode(-1);
            result.setMsg("专家不存在");
            return result;
        }

        // 获取该专家的当前指导学员人数
        int currentCount = expert.getPlaces();

        // 如果当前人数已经达到最大值，则无法分配
        if (currentCount >= MAX_places) {
            result.setCode(-1);
            result.setMsg("分配失败，该专家已达到最大指导学员数。");
            return result;
        }

        // 获取剩余的指导名额
        int remainingSlots = MAX_places - currentCount;

        // 如果待分配的学生超过剩余名额，则返回失败
        if (studentIds.size() > remainingSlots) {
            result.setCode(-1);
            result.setMsg("分配失败，剩余指导名额不足。");
            return result;
        }

        // 将学生分配给专家
        for (Integer studentId : studentIds) {
            try {
                // 需要判断该学生是否已经被分配给其他专家，避免重复分配
                QueryWrapper<Student> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("id", studentId);
                queryWrapper.isNull("expert_id");
                Student existingAssignment = studentMapper.selectOne(queryWrapper);
                System.out.println(existingAssignment);
                if (existingAssignment.getExpertId()!= null) {
                    result.setCode(-1);
                    result.setMsg("分配失败，该学生已经被分配给其他专家。");
                    return result;
                }

                // 执行分配操作
                Student assignment = new Student();
                assignment.setId(studentId);
                assignment.setExpertId(expertId);
                int updateCount = studentMapper.updateById(assignment);

                // 确保更新成功
                if (updateCount == 0) {
                    result.setCode(-1);
                    result.setMsg("分配失败，更新学生信息时出错。");
                    return result;
                }
            } catch (Exception e) {
                // 捕获异常并返回错误信息
                result.setCode(-1);
                result.setMsg("分配失败，发生系统异常：" + e.getMessage());
                return result;
            }
        }

        // 返回成功信息
        result.setCode(0);
        result.setMsg("分配成功");
        result.setData(true);
        return result;

    }

    @Override
    public CommonResult<ApiStudentLoginVO> login(String tel, String password) {
        CommonResult<ApiStudentLoginVO> result = new CommonResult<>();
        try {
            QueryWrapper<Student> userQueryWrapper = new QueryWrapper<>();
            userQueryWrapper.eq("tel", tel).eq("user_pwd", password);
            Student student = studentMapper.selectOne(userQueryWrapper);
            if(student == null){
                result.setCode(-1);
                result.setMsg("用户名或密码错误");
                return result;
            }
            //创建token
            String token = JwtUtil.createToken(student);




            //获取StudentVO
            StudentVO studentVO = getStudentVO(student);
            ApiStudentLoginVO apiStudentLoginVO = new ApiStudentLoginVO();
            apiStudentLoginVO.setStudentVO(studentVO);
            apiStudentLoginVO.setToken(token);

            result.setCode(0);
            result.setData(apiStudentLoginVO);
            result.setMsg("登录成功");
            return result;
        }catch (Exception e){
            result.setCode(-1);
            result.setMsg("登录失败" + e.getMessage());
            return result;
        }
    }




    @Override
    public CommonResult<ApiGetDateLogVO> apiGetDateLog(Long userId, Long projectId, String date) {
        CommonResult<ApiGetDateLogVO> result = new CommonResult<>();
        ApiGetDateLogVO apiGetDateLogVO = new ApiGetDateLogVO();
        try {
            // 解析传递的日期
            LocalDate localDate = LocalDate.parse(date, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            LocalDateTime startOfDay = localDate.atStartOfDay(); // 当天的 00:00:00
            LocalDateTime endOfDay = localDate.atTime(LocalTime.MAX); // 当天的 23:59:59

            // 创建查询条件
            QueryWrapper<Log> wrapper = new QueryWrapper<>();
            wrapper.eq("user_id", userId)
                    .eq("project_id", projectId)
                    .between("log_date", startOfDay, endOfDay); // 使用时间范围匹配

            Log log = logMapper.selectOne(wrapper);
            if(log != null){
                BeanUtils.copyProperties(log,apiGetDateLogVO);
                //根据路径查询所有文件名
                apiGetDateLogVO.setFileNames(getFileNames(log.getUrlFile(), userId, projectId,date));
                apiGetDateLogVO.setImageUrls(getImageFileNames(userId,projectId,log.getUrlImg(),date));
                result.setCode(0);
                result.setData(apiGetDateLogVO);
                result.setMsg("获取日志成功");
            }else{
                result.setCode(-1);
                result.setData(null);
            }
        }catch (Exception e){
            result.setCode(-1);
            result.setMsg("获取日志失败" + e.getMessage());
            result.setData(null);
        }
        return result;
    }

    private List<String> getImageFileNames(Long userId, Long projectId, String urlImg,String date) {
        List<String> fileNames = new ArrayList<>();
        // 指定要查询的路径
        String path = urlImg;
        if(path == null){
            return fileNames;
        }
        File directory = new File(path);

        // 检查路径是否存在且为目录
        if (directory.exists() && directory.isDirectory()) {
            // 获取目录下的所有文件和文件夹
            File[] files = directory.listFiles();
            if (files != null) {
                for (File file : files) {
                    // 打印文件名
                    fileNames.add(FileUploadUtils.FILE_URL+ "DiaryFiles/" + String.valueOf(userId) + "/" + String.valueOf(projectId) + "/"+date+"/"+ "img/"+ file.getName());
                }
            }
        }
        return fileNames;
    }

    private List<String> getFileNames(String url_file, Long StudentId, Long projectId,String date) {
        List<String> fileNames = new ArrayList<>();
        // 指定要查询的路径
        String path = url_file;
        if(url_file == null){
            return fileNames;
        }
        File directory = new File(path);

        // 检查路径是否存在且为目录
        if (directory.exists() && directory.isDirectory()) {
            // 获取目录下的所有文件和文件夹
            File[] files = directory.listFiles();
            if (files != null) {
                for (File file : files) {
                    // 打印文件名
                    fileNames.add(FileUploadUtils.FILE_URL+ "DiaryFiles/" + String.valueOf(StudentId) + "/" + String.valueOf(projectId) + "/" + date+"/"+"file/"+ file.getName());
                }
            }
        }
        return fileNames;
    }

    @Override
    public CommonResult<Boolean> apiInsertAttendence(ApiInsertAttendenceDTO apiInsertAttendenceDTO) {
        CommonResult<Boolean> result = new CommonResult<>();
        try {
            Long studentId = apiInsertAttendenceDTO.getStudentId();
            String lessonDate = apiInsertAttendenceDTO.getLessonDate();
            String timestamp = apiInsertAttendenceDTO.getTimestamp();
            Long courseId = apiInsertAttendenceDTO.getCourseId();

            if(studentId == null || lessonDate == null || timestamp == null || courseId == null){
                result.setCode(-1);
                result.setMsg("参数错误");
            }

            //不能重复签到
            if(attendanceMapper.selectOne(new QueryWrapper<Attendance>().eq("student_id",studentId).eq("time_id",courseId)) != null){
                result.setCode(-2);
                result.setMsg("不能重复签到");
                result.setData(false);
                return result;
            }

            Attendance attendance = new Attendance();
            attendance.setStudentId(studentId);
            attendance.setTimeId(courseId);
            attendance.setState(1);

            // 转换为 Date 对象
            long milliseconds = Long.parseLong(timestamp);
            Date date = new Date(milliseconds);
            attendance.setSignDate(date);

            int insert = attendanceMapper.insert(attendance);
            if(insert == 1){
                result.setCode(0);
                result.setMsg("签到成功");
                result.setData(true);
            }else{
                result.setCode(-1);
                result.setMsg("签到失败");
                result.setData(false);
            }
        }catch (Exception e){
            result.setCode(-1);
            result.setMsg("插入失败" + e.getMessage());
            result.setData(false);
        }

        return result;
    }

    @Override
    public CommonResult<ApiTotalScoreVO> getScoreInfo(Integer userId,Integer projectId) {
        CommonResult<ApiTotalScoreVO> result = new CommonResult<>();
        try{
            Double score1 = homeworkDetailMapper.getAvgerage(userId);
            if(score1==null){
                score1= (double) 0;
            }
            System.out.println(score1);
            // 学生日志成绩
            Double score2 = logMapper.getAverageScore(userId);
            if(score2==null){
                score2= (double) 0;
            }
            System.out.println(score2);
            //考勤成绩
            Double score3 =  calculateAttendanceScore(userId,projectId);
            System.out.println(score3);
            QueryWrapper<Settings> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("id",1);
            Settings settings= settingsMapper.selectOne(queryWrapper);
            double a=settings.getHomeworkRate()/100;
            double b= settings.getLogRate()/100;
            double c= settings.getAttendanceRate()/100;

            Double totalScore = score1*a + score2*b + score3*c;
            System.out.println(totalScore);

            result.setCode(0);
            ApiTotalScoreVO apiTotalScoreVO = new ApiTotalScoreVO();
            apiTotalScoreVO.setUserId(userId);
            apiTotalScoreVO.setTotalscore(totalScore);
            result.setData(apiTotalScoreVO);

        }
        catch (Exception e){
            result.setCode(-1);
            result.setMsg("成绩错误" + e.getMessage());

        }
        return result;
    }

    //考勤分数 带改
    private Double calculateAttendanceScore(Integer studentId,Integer projectId) {
        QueryWrapper<Attendance> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("student_id",studentId);
        //签到人数
        int missedCount = attendanceMapper.selectCount(queryWrapper);

        QueryWrapper<Course> queryWrapper1 = new QueryWrapper<>();
        queryWrapper1.eq("project_id",projectId);

        //一次项目的课程数
        int projectCount = courseMapper.selectCount(queryWrapper1);
        if(projectCount==0){
            return 0.0;
        }

        System.out.println((double)missedCount/projectCount);
        Double a=(100*((double)missedCount/projectCount));
        System.out.println(a);
        return a;
    }

    //修改密码
    @Override
    public CommonResult<Boolean> revisePassword(ApiRevisePwdDTO apiRevisePwdDTO){
        CommonResult<Boolean> result = new CommonResult<>();
        long id = apiRevisePwdDTO.getUserId();
        String userPwd = apiRevisePwdDTO.getPassword();
        try{
            if(id==0 || Objects.equals(userPwd, "")){
                result.setCode(-1);
                result.setMsg("参数错误");
                result.setData(false);
                return result;
            }
            else {
                QueryWrapper<Student> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("id",id);
                Student student = studentMapper.selectOne(queryWrapper);
                student.setUserPwd(userPwd);
                studentMapper.updateById(student);

                result.setCode(0);
                result.setMsg("修改成功");
                result.setData(true);
            }
        }catch (Exception e){
            result.setCode(-1);
            result.setMsg("修改失败" + e.getMessage());
        }
        return result;
    }


}